const ws = require('ws');
const url = require('url');
const HmacSHA256 = require('crypto-js/hmac-sha256');
const Base64 = require('crypto-js/enc-base64');
const UTF8 = require('crypto-js/enc-utf8');

class Spark{
    constructor(SparkConfig, dbContext, SparkVersion){
      this.Config = SparkConfig;
      this.dbContext = dbContext ?? null;
      this.Ver = SparkVersion ?? 3;
    };
    get ws() { return new ws(this.Url()) };// WebSocket
    Url(){
      let UTC_date = new Date(Date.now()).toUTCString();//获取RFC1123时间 .toLocaleString()
      let tmp = `host: spark-api.xf-yun.com\ndate: ${UTC_date}\nGET /v${this.Ver}.1/chat HTTP/1.1`;// 原始tmp 
      let tmp_sha = HmacSHA256(tmp, this.Config.APISecret).toString();
      let signature = Buffer.from(tmp_sha, 'hex').toString('base64');// 最抽象的一集
      let authorization_origin = `api_key="${this.Config.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`;
      let authorization = Base64.stringify(UTF8.parse(authorization_origin));// 最复杂的一集
      // console.log( url.format({
      //   protocol: 'wss',
      //   hostname: 'spark-api.xf-yun.com',
      //   pathname: `/v${this.Ver}.1/chat`,
      //   query: {
      //     authorization: authorization,
      //     date: UTC_date,
      //     host: 'spark-api.xf-yun.com'
      //   }
      // }));

      return url.format({
        protocol: 'wss',
        hostname: 'spark-api.xf-yun.com',
        pathname: `/v${this.Ver}.1/chat`,
        query: {
          authorization: authorization,
          date: UTC_date,
          host: 'spark-api.xf-yun.com'
        }
      });
    };// 获取鉴权URL

    GetReply(MsgText){

      return new Promise((resolve, reject) => {
        let SparkReply = '';
        let wsSpark = this.ws;// 创建websocket连接
        // console.log(MsgText); Debug用的

        
        let SendToSparkMsg = {
          header: {
            app_id: this.Config.APPID,
          },
          parameter: {
            chat: {
              domain: "general"     // 取值[general, generalv2, generalv3], 对应v1.5, v2, v3版本的spark
                       + (this.Ver === 1 ? "" : "v" + this.Ver.toString()),    
              temperature: 0.8,     // 取值[0,1], 取值越高随机性越强
              max_tokens: 2048,     // v1.5, v2, v3取值[1,4096], [1,8192], [1,8192], 模型回答的tokens的最大长度
              top_k: 4,             // 取值为[1,6], 从k个候选中随机选择⼀个
            }
          },
          payload: {
            message: {
              "text": MsgText     // [{ role: "user", content: "" }, { role: "assistant", content: "" }]
            }
          }
        };// 发送给wsSpark的消息对象

        wsSpark.on('open', (err) => {
          if (err) {
            console.log(`[ERROR]  wsSpark_Open_ERR: ${err}`);
            reject(err);
          }
          wsSpark.send(JSON.stringify(SendToSparkMsg));
          console.log('[Spark]  SparkAPI鉴权成功 回答中');
        });// 发送SendToSparkMsg

        wsSpark.on('message', (data, err) => {
          if (err) {
            console.log(`[ERROR]  wsSpark_Message_ERR: ${err}`);
            reject(err);
          }else if (JSON.parse(data).header.code != 0){
            switch (JSON.parse(data).header.code){

              case 10000:case 10001:case 10002: console.log('[ERROR]  ws错误'+ JSON.parse(data).header.code); resolve("SparkAPI_WebSocket错误"); break;
              case 10003:case 10004:case 10005: console.log('[ERROR]  ws错误'+ JSON.parse(data).header.code); resolve("SparkAPI消息格式错误"); break;
              case 10013:case 10014: resolve("什么逆天发言(｀へ´)? 叉出去"); break;
              case 11201: resolve("日流超限了<emoji:289>下班<emoji:355>"); break;
              case 11202:case 11203: resolve("发得太快了<emoji:34>让我反应一下<emoji:34>"); break;
              default: resolve("李再嗦神魔？" + JSON.parse(data).header.code);
            };
          }else {
            SparkReply += JSON.parse(data).payload.choices.text[0].content;
            if (JSON.parse(data).payload.choices.status == 2) {
              resolve({content: SparkReply, token: JSON.parse(data).payload.usage.text.total_tokens});
            };
          };
        });

      });
    };// getReply
    
    async Ping(){
      let time = Date.now();
      return new Promise((resolve, reject) => {
        this.ws.on('open', (err) => {
          if(err) reject(err);
          else    resolve(Date.now() - time);
        })
      });
    };

};

module.exports = Spark;

// let spark = new Spark(SparkConfig);
// spark.getReply("你好");
